import { defineComponent, ref, watch, computed, onMounted, onBeforeUnmount, openBlock, createElementBlock, createElementVNode, renderSlot, normalizeClass, Fragment, renderList, createVNode, unref, toDisplayString, createCommentVNode } from "vue";
import "../icons/index.mjs";
import { Progress } from "ant-design-vue";
import FileIcon from "../icons/file-icon.vue.mjs";
const _hoisted_1 = { class: "me-upload-file" };
const _hoisted_2 = ["multiple"];
const _hoisted_3 = { class: "me-upload-left" };
const _hoisted_4 = { class: "me-upload-content" };
const _hoisted_5 = { class: "me-upload-name" };
const _hoisted_6 = { class: "me-upload-progress" };
const CUT_SIZE = 5 * 1024 * 1024;
const ALLOW_SIZE = 200 * 1024 * 1024;
const _sfc_main = /* @__PURE__ */ defineComponent({
  ...{
    name: "me-upload-file"
  },
  __name: "upload-file",
  props: {
    multiple: { type: Boolean, default: false },
    url: { default: "" },
    isCut: { type: Boolean, default: false },
    cutSize: { default: CUT_SIZE },
    allowTypes: { default() {
      return ["mp3", "mp4", "docx", "doc", "png", "jpg", "zip", "jpeg", "gif", "xlsx", "xlsm", "xlx", "xls", "rar", "ppt", "pptx", "pdf", "bmp", "json", "html"];
    } },
    allowSize: { default: ALLOW_SIZE },
    headers: { default() {
      return {};
    } },
    fieldName: { default: "file" },
    fileList: { default() {
      return [];
    } },
    formData: { default() {
      return {};
    } },
    showPreview: { type: Boolean, default: false },
    autoRemovePreview: { type: Boolean, default: false },
    beforeUpload: {},
    afterUpload: {},
    enctype: { default: "formdata" },
    allowClearBeforeUpload: { type: Boolean, default: false }
  },
  emits: [
    "invalid-type",
    "invalid-size",
    "update:fileList",
    "progress",
    "success",
    "fail",
    "abort",
    "network-interrupt",
    "error"
  ],
  setup(__props, { emit: __emit }) {
    const count = ref(0);
    const props = __props;
    const emits = __emit;
    const inputRef = ref();
    const uploadList = ref(props.fileList || []);
    const uploadChunkList = ref([]);
    watch(() => props.fileList, () => {
      uploadList.value = props.fileList;
    });
    const onClick = () => {
      inputRef.value.value = "";
      inputRef.value.click();
    };
    const isShowPreview = computed(() => {
      if (props.showPreview && props.autoRemovePreview) {
        return count.value !== uploadList.value.length;
      } else if (props.showPreview) {
        return true;
      }
      return false;
    });
    const checkFileType = (file, types) => {
      const arr = file.name.split(".");
      const extName = arr.length > 1 ? arr[arr.length - 1] : "";
      if (types.length > 0 && !(types == null ? void 0 : types.includes(extName))) {
        return false;
      }
      return true;
    };
    const checkFileSize = (file, maxSize) => {
      if (file.size > maxSize) {
        return false;
      }
      return true;
    };
    const upload = (xhr, options) => {
      let { url, headers, fieldName, file, progress, abort, formData, enctype, cutIndex } = options;
      return new Promise((resolve, reject) => {
        formData = formData[cutIndex] || formData;
        url = (formData == null ? void 0 : formData.url) || url;
        const fd = new FormData();
        if ("fieldName" in formData) {
          fd.append(formData.fieldName, file);
        } else {
          fd.append(fieldName, file);
        }
        if (enctype === "querystring") {
          let arr = [];
          for (let key in formData) {
            if (key !== "fieldName") {
              arr.push(`${key}=${formData[key]}`);
            }
          }
          url += `?${arr.join("&")}`;
        } else {
          for (let key in formData) {
            fd.append(key, formData[key]);
          }
        }
        xhr.open("post", url);
        for (let key in headers) {
          xhr.setRequestHeader(key, headers[key]);
        }
        xhr.upload.onprogress = (evt) => {
          progress(evt);
        };
        xhr.onabort = (evt) => {
          abort(evt);
        };
        xhr.onload = () => {
          try {
            const response = JSON.parse(xhr.response);
            resolve(response);
          } catch (err) {
            reject(err);
          }
        };
        xhr.onerror = () => {
          reject(xhr.response);
        };
        xhr.send(fd);
      });
    };
    const createChunk = async (file, index, chunkSize) => {
      return new Promise((resolve) => {
        const start = index * chunkSize;
        const end = start + chunkSize;
        const fileChunk = file.slice(start, end);
        resolve({
          blob: fileChunk,
          start,
          end,
          index
        });
      });
    };
    const isPromise = (obj) => {
      return obj && typeof obj === "object" && obj.constructor === Promise;
    };
    const cutFile = async (file, cutSize) => {
      const chunkCount = Math.ceil(file.size / cutSize);
      const promises = [];
      for (let i = 0; i < chunkCount; i++) {
        promises.push(createChunk(file, i, cutSize));
      }
      const result = await Promise.all(promises);
      return result;
    };
    const handleInputChange = async () => {
      if (!navigator.onLine) {
        emits("network-interrupt");
        return;
      }
      const { allowClearBeforeUpload, headers, isCut, url, allowSize, allowTypes, fieldName, formData, beforeUpload, cutSize, enctype, afterUpload } = props;
      const files = inputRef.value.files;
      if (allowClearBeforeUpload) {
        clearData();
      }
      const len = uploadList.value.length;
      for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const k = i + len;
        uploadList.value[k] = {
          file,
          percent: 0,
          status: "pendding"
        };
        emits("update:fileList", uploadList.value);
        if (beforeUpload && typeof beforeUpload === "function") {
          const beforeUploadRes = beforeUpload(uploadList.value[k]);
          if (beforeUploadRes === false) {
            continue;
          } else if (beforeUploadRes === true) {
          } else {
            if (isPromise(beforeUploadRes)) {
              const result = await Promise.resolve(beforeUploadRes);
              Object.assign(formData, result);
            } else if (typeof beforeUploadRes === "object") {
              Object.assign(formData, beforeUploadRes);
            } else {
              throw new Error("beforeUpload函数返回的值必须是一个对象");
            }
          }
        }
        if (!checkFileType(file, allowTypes)) {
          emits("invalid-type", file);
          continue;
        }
        ;
        if (!checkFileSize(file, allowSize)) {
          emits("invalid-size", file);
          continue;
        }
        if (isCut && cutSize < file.size) {
          const promises = [];
          const chunks = await cutFile(file, cutSize);
          for (let j = 0; j < chunks.length; j++) {
            const chunk = chunks[j];
            const xhr = new XMLHttpRequest();
            uploadChunkList.value[j] = {
              file: chunk.blob,
              percent: 0
            };
            promises.push(upload(xhr, {
              fieldName,
              url,
              headers,
              file: chunk.blob,
              formData,
              enctype,
              cutIndex: j,
              progress(evt) {
                const percent = Math.max(parseInt((evt.loaded / evt.total * 100).toString()) - 1, 0);
                uploadChunkList.value[j].percent = percent;
                const temp = uploadChunkList.value.reduce((per, item) => per += item.percent, 0);
                uploadList.value[k].percent = parseInt((temp / uploadChunkList.value.length).toString());
                emits("progress", file, chunk, evt);
              },
              abort(evt) {
                emits("abort", file, chunk, evt);
              }
            }));
          }
          try {
            const result = await Promise.all(promises);
            if (typeof afterUpload === "function") {
              if (afterUpload(result)) {
                uploadList.value[k].percent = 100;
                uploadList.value[k].status = "success";
                emits("success", uploadList.value[k], result);
              } else {
                uploadList.value[k].status = "fail";
                emits("fail", uploadList.value[k], result);
              }
            }
          } catch (err) {
            if (err) {
              uploadList.value[k].status = "fail";
              emits("error", uploadList.value[k], err);
            } else {
              uploadList.value[k].status = "fail";
              emits("network-interrupt");
            }
          }
        } else {
          const xhr = new XMLHttpRequest();
          upload(xhr, {
            fieldName,
            url,
            headers,
            file,
            formData,
            enctype,
            progress(evt) {
              const percent = Math.max(parseInt((evt.loaded / evt.total * 100).toString()) - 1, 0);
              uploadList.value[k].percent = percent;
              emits("progress", file, evt);
            },
            abort(evt) {
              emits("abort", file, evt);
            }
          }).then((res) => {
            if (typeof afterUpload === "function") {
              if (afterUpload(res)) {
                uploadList.value[k].percent = 100;
                uploadList.value[k].status = "success";
                setTimeout(() => {
                  count.value++;
                }, 300);
                emits("success", uploadList.value[k], res);
              } else {
                uploadList.value[k].status = "fail";
                emits("fail", uploadList.value[k], res);
              }
            }
          }).catch((err) => {
            if (err) {
              uploadList.value[k].status = "fail";
              emits("error", uploadList.value[k], err);
            } else {
              uploadList.value[k].status = "fail";
              emits("network-interrupt");
            }
          });
        }
      }
    };
    const bindInputChange = () => {
      inputRef.value.addEventListener("change", handleInputChange);
    };
    const unbindInputChange = () => {
      inputRef.value.removeEventListener("change", handleInputChange);
    };
    const clearData = () => {
      uploadChunkList.value = [];
      uploadList.value = [];
      count.value = 0;
    };
    onMounted(() => {
      bindInputChange();
    });
    onBeforeUnmount(() => {
      unbindInputChange();
      clearData();
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1, [
        createElementVNode("span", {
          class: "me-upload-file-button",
          onClick
        }, [
          renderSlot(_ctx.$slots, "default")
        ]),
        createElementVNode("input", {
          ref_key: "inputRef",
          ref: inputRef,
          type: "file",
          hidden: "",
          multiple: _ctx.multiple
        }, null, 8, _hoisted_2),
        isShowPreview.value ? renderSlot(_ctx.$slots, "preview", { key: 0 }, () => [
          createElementVNode("div", {
            class: normalizeClass({ "me-upload-preview": uploadList.value.length > 0 })
          }, [
            (openBlock(true), createElementBlock(Fragment, null, renderList(uploadList.value, (item, index) => {
              return openBlock(), createElementBlock("div", {
                class: "me-upload-preview-list",
                key: index
              }, [
                createElementVNode("div", _hoisted_3, [
                  createVNode(unref(FileIcon), { class: "me-upload-left-icon" })
                ]),
                createElementVNode("div", _hoisted_4, [
                  createElementVNode("div", _hoisted_5, toDisplayString(item.file.name), 1),
                  createElementVNode("div", _hoisted_6, [
                    createVNode(unref(Progress), {
                      percent: item.percent
                    }, null, 8, ["percent"])
                  ])
                ])
              ]);
            }), 128))
          ], 2)
        ]) : createCommentVNode("", true)
      ]);
    };
  }
});
export {
  _sfc_main as default
};
//# sourceMappingURL=upload-file.vue2.mjs.map
